package com.robot.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jayway.jsonpath.JsonPath;
import com.robot.constant.BuildTestStatus;
import com.robot.dto.RunTestContext;
import com.robot.model.BuildTestCaseDo;
import com.robot.model.BuildTestDo;
import com.robot.util.DocumentUtil;
import com.robot.util.ReportLogUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.test.util.AssertionErrors;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created with IntelliJ IDEA.
 * User: li
 * Date: 2019/12/1
 * Time: 13:40
 * PROJECT：robot
 * PACKAGE: com.robot
 *
 * @author:55324936@qq.com To change this template use File | Settings | File Templates.
 */
@Slf4j
@Service
public class AssertService {

    @Autowired
    DocumentUtil documentUtil;
    /**
     * 校验实际运行结果与预期结果是否一致
     **/
    public void assertResult(RunTestContext runTestContext) {
        BuildTestCaseDo buildTestCaseDo = runTestContext.getBuildTestCaseDo();
        String actualResult = buildTestCaseDo.getActualResult();
        String expectResult = buildTestCaseDo.getExpectResult();
        Integer assertType = buildTestCaseDo.getAssertType();
        buildTestCaseDo.setStatus(BuildTestStatus.PASS);
        ReportLogUtil reportLogUtil = runTestContext.getReportLogUtil();
        switch (assertType) {
            case 1:
                if (!expectResult.equalsIgnoreCase(actualResult)) {
                    buildTestCaseDo.setStatus(BuildTestStatus.FAIL);
                }
                break;
            case 2:
                if (!actualResult.contains(expectResult)) {
                    buildTestCaseDo.setStatus(BuildTestStatus.FAIL);
                }
                break;
            case 3:
                if (actualResult.contains(expectResult)) {
                    buildTestCaseDo.setStatus(BuildTestStatus.FAIL);
                }
                break;
            case 4:
                /**jsonPath**/
                String ex = buildTestCaseDo.getExpression();
                if (!StringUtils.isEmpty(ex)) {
                    JSONArray jsonArray = null;
                    try {
                        jsonArray = JSON.parseArray(ex);
                    }catch (Exception e){
                        log.error("反序列化失败",e);
                        reportLogUtil.writeRedSpan("反序列化表达式异常,请检查表达式内容");
                    }
                    Iterator iterator =jsonArray.iterator();
                    while (iterator.hasNext()){
                        JSONObject exStr= (JSONObject) iterator.next();
                        String exValue=exStr.getString("value");
                        //$.object.age
                        try {
                            Object expect = JsonPath.read(expectResult, exValue);
                            Object actual = JsonPath.read(actualResult, exValue);
                            try {
                                AssertionErrors.assertEquals("", expect, actual);
                            } catch (AssertionError error) {
                                buildTestCaseDo.setStatus(BuildTestStatus.FAIL);
                                reportLogUtil.writeRedSpan("测试用例[" + buildTestCaseDo.getTestCaseName() + "]断言校验未通过");
                                reportLogUtil.writeRedSpan("测试用例[" + buildTestCaseDo.getTestCaseName() + "]" + error.getMessage());
                                break;
                            }
                        }catch (Exception e){
                            buildTestCaseDo.setStatus(BuildTestStatus.FAIL);
                            reportLogUtil.writeRedSpan("测试用例[" + buildTestCaseDo.getTestCaseName() + "]断言校验未通过");
                            reportLogUtil.writeRedSpan("测试用例[" + buildTestCaseDo.getTestCaseName() + "]" + e.getMessage());
                            break;
                        }
                    }
                }
                break;
            case 5:
                /**正则表达式**/
                String matcher = buildTestCaseDo.getExpression();
                if(!StringUtils.isEmpty(matcher)){
                    JSONArray jsonArray =null;
                    try {
                         jsonArray = JSON.parseArray(matcher);
                    }catch (Exception e){
                        log.error("反序列化失败",e);
                        reportLogUtil.writeRedSpan("反序列化表达式异常,请检查表达式内容");
                    }
                    Iterator iterator =jsonArray.iterator();
                    while (iterator.hasNext()) {
                        JSONObject exStr = (JSONObject) iterator.next();
                        Pattern pattern = Pattern.compile(exStr.getString("value"));
                        Matcher matcherExpect =pattern.matcher(expectResult);
                        Object expect = null;
                        if(matcherExpect.find()){
                            expect=matcherExpect.group();
                        }
                        Object actual=null;
                        Matcher actualExpect =pattern.matcher(expectResult);
                        if(actualExpect.find()){
                            actual=matcherExpect.group();
                        }
                        try {
                            AssertionErrors.assertEquals("", expect, actual);
                        } catch (AssertionError error) {
                            buildTestCaseDo.setStatus(BuildTestStatus.FAIL);
                            reportLogUtil.writeRedSpan("测试用例[" + buildTestCaseDo.getTestCaseName() + "]断言校验未通过");
                            reportLogUtil.writeRedSpan("测试用例[" + buildTestCaseDo.getTestCaseName() + "]" + error.getMessage());
                            break;
                        }
                    }
                }
                break;
            default:
                Document expectDocument;
                Document actualDocument;
                expectDocument=documentUtil.getDocument(expectResult);
                actualDocument=documentUtil.getDocument(actualResult);
                XPath xPath =XPathFactory.newInstance().newXPath();
                String xx = buildTestCaseDo.getExpression();
                if(!StringUtils.isEmpty(xx)) {
                    JSONArray jsonArray = null;
                    try {
                        jsonArray = JSON.parseArray(xx);
                    } catch (Exception e) {
                        log.error("反序列化失败", e);
                        reportLogUtil.writeRedSpan("反序列化表达式异常,请检查表达式内容");
                    }
                    Iterator iterator =jsonArray.iterator();
                    while (iterator.hasNext()) {
                        JSONObject exStr = (JSONObject) iterator.next();
                        String exValue=exStr.getString("value");
                        Object expectValue;
                        Object actualValue;
                        try {
                            Node expectNode =(Node) xPath.evaluate(exValue,expectDocument,XPathConstants.NODE);
                            expectValue=expectNode.getNodeValue();
                            Node actualNode =(Node) xPath.evaluate(exValue,actualDocument,XPathConstants.NODE);
                            actualValue=actualNode.getNodeValue();
                        } catch (XPathExpressionException e) {
                            buildTestCaseDo.setStatus(BuildTestStatus.FAIL);
                            reportLogUtil.writeRedSpan("测试用例[" + buildTestCaseDo.getTestCaseName() + "]断言校验未通过,表达式获取异常");
                            reportLogUtil.writeRedSpan("测试用例[" + buildTestCaseDo.getTestCaseName() + "]" + e.getMessage());
                            break;
                        }
                        try {
                            AssertionErrors.assertEquals("", expectValue, actualValue);
                        } catch (AssertionError error) {
                            buildTestCaseDo.setStatus(BuildTestStatus.FAIL);
                            reportLogUtil.writeRedSpan("测试用例[" + buildTestCaseDo.getTestCaseName() + "]断言校验未通过");
                            reportLogUtil.writeRedSpan("测试用例[" + buildTestCaseDo.getTestCaseName() + "]" + error.getMessage());
                            break;
                        }
                    }
                }
                /**xpath**/
        }
        if (buildTestCaseDo.getStatus().intValue() == BuildTestStatus.PASS) {
            reportLogUtil.writeGreenSpan(buildTestCaseDo.getTestCaseName() + "断言通过");
        } else {
            reportLogUtil.writeRedSpan("测试用例:" + buildTestCaseDo.getTestCaseName() + "断言失败");
        }
    }
}
